import sqlite3
from pathlib import Path
from typing import Optional, Union

from common.utils.utils_log import AntLogger


def find_project_root(
    start_path: Path, markers: list = [".git", "pyproject.toml"]
) -> Path:
    """
    从起始路径向上查找项目根目录。

    通过查找如 .git 目录或 pyproject.toml 等标记文件来确定根目录。
    这是最可靠的方法，因为它不依赖于当前工作目录。

    :param start_path: 开始搜索的路径，通常是 Path(__file__).parent。
    :param markers: 用于标识项目根目录的文件或文件夹列表。
    :return: 找到的项目根目录的 Path 对象。
    :raises FileNotFoundError: 如果向上查找到文件系统根目录也未找到标记。
    """
    current_path = start_path.resolve()
    while not any((current_path / marker).exists() for marker in markers):
        if current_path.parent == current_path:
            # 如果已经到达文件系统的根目录（例如 '/', 'C:\'），则抛出错误
            raise FileNotFoundError(
                f"无法从 '{start_path}' 向上找到项目根目录标记 ({markers})。"
            )
        current_path = current_path.parent
    return current_path


class DatabaseInitializer:

    def initialize_database(self):
        """
        初始化数据库，包括创建表和导入初始数据
        :return: 是否初始化成功
        """
        try:

            # 获取数据库初始化器
            AntLogger.info("数据库初始化....")
            self.execute()
            AntLogger.error("数据库初始化完成")
        except Exception as e:
            AntLogger.error(f"初始化数据库时发生错误: {e}")
            return False

    """
    数据库自动初始化器。

    它能自动发现项目根目录，并在此基础上定位数据库文件和递归查找初始化SQL脚本。
    """

    def __init__(self, sql_script_path: Optional[Union[str, Path]] = None):
        """
        初始化数据库初始化器。

        它会自动执行以下操作：
        1. 查找项目根目录。
        2. 定位根目录下的 'stock_monitor.db'。
        3. 除非用户明确指定路径，否则将递归搜索 'init_db.sql'。

        :param sql_script_path: (可选) 明确指定 init_db.sql 的路径。如果提供，将跳过自动搜索。
        """
        try:
            # 1. 自动定位项目根目录
            self.project_root = find_project_root(Path(__file__).parent)
            print(f"✅ 成功定位项目根目录: {self.project_root}")

            # 2. 数据库路径固定在根目录下
            self.db_path = self.project_root / "stock_monitor.db"
            print(f"➡️ 数据库路径已设定: {self.db_path}")

            # 3. 查找 init_db.sql 文件
            if sql_script_path:
                # 如果用户明确提供了路径，则直接使用
                self.sql_script_path = Path(sql_script_path)
                if not self.sql_script_path.is_file():
                    raise FileNotFoundError(
                        f"用户指定的SQL文件不存在: {self.sql_script_path}"
                    )
                print(f"➡️ 使用用户指定的SQL文件: {self.sql_script_path}")
            else:
                # 否则，在项目根目录下递归搜索
                self.sql_script_path = self._find_sql_recursively("init_db.sql")
                print(f"✅ 成功查找到SQL文件: {self.sql_script_path}")

        except FileNotFoundError as e:
            print(f"❌ 初始化失败: {e}")
            # 重新抛出异常，使外部调用者知道初始化失败
            raise

    def _find_sql_recursively(self, filename: str) -> Path:
        """在项目根目录下递归搜索文件。"""
        print(f"正在从 '{self.project_root}' 开始递归搜索 '{filename}'...")
        # 使用 rglob 进行递归搜索
        results = list(self.project_root.rglob(filename))

        if not results:
            raise FileNotFoundError(f"未能在项目根目录及其子目录中找到 '{filename}'。")

        if len(results) > 1:
            print(
                f"⚠️ 警告: 找到多个 '{filename}' 文件，将使用第一个查找到的: {results[0]}"
            )

        return results[0]

    def execute(self):
        """
        连接到数据库并执行找到的SQL脚本。
        整个过程是事务性的，失败则回滚。
        """
        print("-" * 50)
        print(f"🚀 开始执行数据库初始化...")
        try:
            # 确保数据库文件的父目录存在
            self.db_path.parent.mkdir(parents=True, exist_ok=True)

            # 使用 'with' 语句自动管理连接和事务
            with sqlite3.connect(self.db_path) as conn:
                with open(self.sql_script_path, "r", encoding="utf-8") as f:
                    sql_script = f.read()

                # executescript 可以安全地执行包含多条语句的脚本
                conn.executescript(sql_script)

            print("🎉 数据库初始化成功完成！")

        except sqlite3.Error as e:
            print(f"❌ 数据库操作失败，所有更改已回滚。错误: {e}")
        except Exception as e:
            print(f"❌ 发生未知错误: {e}")
